package cloud.tianai.nio.channel;

import cloud.tianai.nio.handler.ChannelPipeline;
import cloud.tianai.nio.loop.EventLoop;
import cloud.tianai.nio.loop.NioEventLoop;
import lombok.Getter;
import lombok.SneakyThrows;

import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;

@Getter
public abstract class AbstractNioChannel implements Channel {

    /** 父通道. */
    private final Channel parent;
    /** 绑定的事件循环器. */
    private volatile EventLoop eventLoop;
    /** 管道. */
    private final ChannelPipeline pipeline;
    /** java的channel 包括ServerSocketChannel和SocketChannel. */
    private final SelectableChannel javaChannel;
    /** 感兴趣的事件. */
    protected final int interestOp;
    /** 注册后返回的selection. */
    protected SelectionKey selectionKey;

    @SneakyThrows(IOException.class)
    public AbstractNioChannel(Channel parent, SelectableChannel javaChannel, int interestOp) {
        this.parent = parent;
        pipeline = newChannelPipeline();
        this.javaChannel = javaChannel;
        this.interestOp = interestOp;
        // 设置为非阻塞
        getJavaChannel().configureBlocking(false);
    }

    @Override
    public void listen() {
        doListen();
    }

    @Override
    public void write(Object obj) throws IOException {
        getPipeline().write(obj);
    }

    @Override
    @SneakyThrows(IOException.class)
    public void close() {
        getJavaChannel().close();
    }


    protected void doListen() {
        // 设置监听的事件类型
        selectionKey.interestOps(interestOp);

    }

    protected ChannelPipeline newChannelPipeline() {
        return new ChannelPipeline(this);
    }


    /**
     * Channel绑定eventLoop
     *
     * @param eventLoop
     */
    @Override
    public final void register(EventLoop eventLoop) {
        // 省去乱七八遭的判断，源码实在内部类Unsafe下，所以是：AbstractChannel.this
        this.eventLoop = eventLoop;
        // 启动eventLoop, 并用eventLoop执行注册事件
        eventLoop.execute(this::doRegister);
    }

    @Override
    public boolean isConnect() {
        return true;
    }

    /**
     * 实际注册
     */
    @SneakyThrows({IOException.class})
    protected void doRegister() {
        // 注册绑定selector
        selectionKey = getJavaChannel().register(((NioEventLoop) this.getEventLoop()).unwrappedSelector(), 0, this);
        // 开始读取感兴趣事件
        listen();
    }


    /**
     * eventLoop监听到事件后的回调函数
     */
    public void handle(SelectionKey k) throws IOException {
        int readyOps = k.readyOps();
        if ((readyOps & interestOp) != 0 || readyOps == 0) {
            doHandle(k);
        }
    }

    /**
     * 监听到事件后执行回调
     *
     * @param k SelectionKey
     */
    protected abstract void doHandle(SelectionKey k) throws IOException;
}
